using System.IO;
using RobotBattle2.Scripting;
using System.Collections.Generic;

namespace RobotBattle2.Rsl2 {


using System;

internal partial class Parser {
	const int _EOF = 0;
	const int _identifier = 1;
	const int _number = 2;
	const int _string = 3;
	const int maxT = 44;

	const bool T = true;
	const bool x = false;
	const int minErrDist = 2;
	
	public Scanner scanner;

	public Token t;    // last recognized token
	public Token la;   // lookahead token
	int errDist = minErrDist;



	public Parser(Scanner scanner) {
		this.scanner = scanner;
	}
	
	void Get () {
		for (;;) {
			t = la;
			la = scanner.Scan();
			if (la.kind <= maxT) { ++errDist; break; }

			la = t;
		}
	}
	
	void Expect (int n) {
		if (la.kind==n) Get(); else { SynErr(n); }
	}
	
	bool StartOf (int s) {
		return set[s, la.kind];
	}
	
	void ExpectWeak (int n, int follow) {
		if (la.kind == n) Get();
		else {
			SynErr(n);
			while (!StartOf(follow)) Get();
		}
	}

	bool WeakSeparator(int n, int syFol, int repFol) {
		int kind = la.kind;
		if (kind == n) {Get(); return true;}
		else if (StartOf(repFol)) {return false;}
		else {
			SynErr(n);
			while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {
				Get();
				kind = la.kind;
			}
			return StartOf(syFol);
		}
	}

	void Grammar() {
		this.Script = new Script(); 
		MethodDeclaration funcdecl; 
		MethodDeclaration(out funcdecl);
		this.Script.Methods.Add(funcdecl); 
		while (la.kind == 1) {
			MethodDeclaration(out funcdecl);
			this.Script.Methods.Add(funcdecl); 
		}
	}

	void MethodDeclaration(out MethodDeclaration funcdecl) {
		funcdecl = new MethodDeclaration(); 
		Expect(1);
		funcdecl.Name = t; 
		if (la.kind == 4) {
			ExpectWeak(4, 1);
			if (la.kind == 1) {
				Get();
				funcdecl.Parameters.Add(t); 
				while (WeakSeparator(5,2,3) ) {
					Expect(1);
					funcdecl.Parameters.Add(t); 
				}
			}
			ExpectWeak(6, 4);
		}
		Expect(7);
		StatementList(funcdecl.Statements);
		Expect(8);
	}

	void StatementList(StatementCollection list) {
		while (StartOf(5)) {
			Statement stmt; 
			Statement(out stmt);
			list.Add(stmt); 
		}
	}

	void Statement(out Statement stmt) {
		stmt = null; 
		switch (la.kind) {
		case 13: {
			VariableDeclarationStatement(out stmt);
			break;
		}
		case 14: {
			IfStatement(out stmt);
			break;
		}
		case 18: {
			WhileLoopStatement(out stmt);
			break;
		}
		case 21: {
			ReturnStatement(out stmt);
			break;
		}
		case 9: {
			Get();
			ExpectWeak(10, 6);
			stmt = new NextLoopStatement(); 
			break;
		}
		case 11: {
			Get();
			ExpectWeak(10, 6);
			stmt = new BreakLoopStatement(); 
			break;
		}
		case 1: case 2: case 3: case 4: case 33: case 34: case 39: case 40: {
			Expression expr; 
			Expression(out expr);
			stmt = new ExpressionStatement(expr); 
			if (la.kind == 12) {
				Get();
				Expression value; 
				Expression(out value);
				stmt = new AssignmentStatement(expr, value); 
			}
			ExpectWeak(10, 6);
			break;
		}
		default: SynErr(45); break;
		}
	}

	void VariableDeclarationStatement(out Statement stmt) {
		Expect(13);
		var vardeclstmt = new VariableDeclarationStatement(); 
		VariableDeclaration(vardeclstmt.Variables);
		stmt = vardeclstmt; 
		while (WeakSeparator(5,2,7) ) {
			VariableDeclaration(vardeclstmt.Variables);
		}
		ExpectWeak(10, 6);
	}

	void IfStatement(out Statement stmt) {
		Expect(14);
		var ifStmt = new IfStatement(); 
		stmt = ifStmt; 
		Expect(4);
		Expression condition; 
		Expression(out condition);
		ifStmt.Condition = condition; 
		Expect(6);
		StatementList(ifStmt.TrueStatements);
		while (la.kind == 15) {
			Get();
			var elseIfStmt = new IfStatement(); 
			Expect(4);
			Expression(out condition);
			elseIfStmt.Condition = condition; 
			Expect(6);
			ifStmt.FalseStatements.Add(elseIfStmt); 
			StatementList(elseIfStmt.TrueStatements);
			ifStmt = elseIfStmt; 
		}
		if (la.kind == 16) {
			Get();
			StatementList(ifStmt.FalseStatements);
		}
		Expect(17);
	}

	void WhileLoopStatement(out Statement stmt) {
		Expect(18);
		var whileStmt = new WhileLoopStatement(); 
		stmt = whileStmt; 
		Expect(4);
		Expression condition; 
		Expression(out condition);
		whileStmt.Condition = condition; 
		Expect(6);
		StatementList(whileStmt.Statements);
		if (la.kind == 19) {
			Get();
		} else if (la.kind == 20) {
			Get();
		} else SynErr(46);
	}

	void ReturnStatement(out Statement stmt) {
		stmt = null; 
		Expect(21);
		if (StartOf(8)) {
			Expression value; 
			Expression(out value);
			stmt = new ReturnStatement(value); 
		} else if (la.kind == 10) {
			stmt = new ReturnStatement(); 
		} else SynErr(47);
		ExpectWeak(10, 6);
	}

	void Expression(out Expression expr) {
		expr = null; 
		LogicalAndExpression(out expr);
		Expression right; 
		while (la.kind == 22 || la.kind == 23) {
			if (la.kind == 22) {
				Get();
				LogicalAndExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Or); 
			} else {
				Get();
				LogicalAndExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Or); 
			}
		}
	}

	void VariableDeclaration(IList<VariableDeclaration> list) {
		Expect(1);
		var name = t; 
		Expression init = null; 
		if (la.kind == 12) {
			Get();
			Expression(out init);
		}
		list.Add(new VariableDeclaration(name, init)); 
	}

	void LogicalAndExpression(out Expression expr) {
		expr = null; 
		EqualityExpression(out expr);
		Expression right; 
		while (la.kind == 24 || la.kind == 25) {
			if (la.kind == 24) {
				Get();
				EqualityExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.And); 
			} else {
				Get();
				EqualityExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.And); 
			}
		}
	}

	void EqualityExpression(out Expression expr) {
		expr = null; 
		RelationalExpression(out expr);
		Expression right; 
		while (la.kind == 26 || la.kind == 27 || la.kind == 28) {
			if (la.kind == 26) {
				Get();
				RelationalExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.NotEqual); 
			} else if (la.kind == 27) {
				Get();
				RelationalExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.NotEqual); 
			} else {
				Get();
				RelationalExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Equal); 
			}
		}
	}

	void RelationalExpression(out Expression expr) {
		expr = null; 
		AdditiveExpression(out expr);
		Expression right; 
		while (StartOf(9)) {
			if (la.kind == 29) {
				Get();
				AdditiveExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.GreaterEqual); 
			} else if (la.kind == 30) {
				Get();
				AdditiveExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Greater); 
			} else if (la.kind == 31) {
				Get();
				AdditiveExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Less); 
			} else {
				Get();
				AdditiveExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.LessEqual); 
			}
		}
	}

	void AdditiveExpression(out Expression expr) {
		expr = null; 
		MultiplicativeExpression(out expr);
		Expression right; 
		while (la.kind == 33 || la.kind == 34) {
			if (la.kind == 33) {
				Get();
				MultiplicativeExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Add); 
			} else {
				Get();
				MultiplicativeExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Subtract); 
			}
		}
	}

	void MultiplicativeExpression(out Expression expr) {
		expr = null; 
		ExponentialExpression(out expr);
		Expression right; 
		while (la.kind == 35 || la.kind == 36 || la.kind == 37) {
			if (la.kind == 35) {
				Get();
				ExponentialExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Multiply); 
			} else if (la.kind == 36) {
				Get();
				ExponentialExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Divide); 
			} else {
				Get();
				ExponentialExpression(out right);
				expr = new BinaryExpression(expr, right, BinaryOperator.Modulo); 
			}
		}
	}

	void ExponentialExpression(out Expression expr) {
		expr = null; 
		UnaryExpression(out expr);
		Expression right; 
		if (la.kind == 38) {
			Get();
			ExponentialExpression(out right);
			expr = new BinaryExpression(expr, right, BinaryOperator.Multiply); 
		}
	}

	void UnaryExpression(out Expression expr) {
		expr = null; 
		if (la.kind == 33) {
			Get();
			AtomicExpression(out expr);
			expr = new UnaryExpression(expr, UnaryOperator.Plus); 
		} else if (la.kind == 34) {
			Get();
			AtomicExpression(out expr);
			expr = new UnaryExpression(expr, UnaryOperator.Minus); 
		} else if (StartOf(10)) {
			AtomicExpression(out expr);
		} else SynErr(48);
	}

	void AtomicExpression(out Expression expr) {
		expr = null; 
		switch (la.kind) {
		case 4: {
			Get();
			Expression(out expr);
			Expect(6);
			break;
		}
		case 2: {
			Get();
			expr = new ConstantExpression(t, ParseNumber(t.val)); 
			break;
		}
		case 3: {
			Get();
			expr = new ConstantExpression(t, ParseString(t.val)); 
			break;
		}
		case 39: {
			Get();
			expr = new ConstantExpression(t, true); 
			break;
		}
		case 40: {
			Get();
			expr = new ConstantExpression(t, false); 
			break;
		}
		case 1: {
			VariableExpression(out expr);
			break;
		}
		default: SynErr(49); break;
		}
	}

	void VariableExpression(out Expression expr) {
		Expect(1);
		expr = new VariableExpression(t); 
		while (la.kind == 41 || la.kind == 42) {
			if (la.kind == 41) {
				Get();
				Expect(1);
				expr = new PropertyExpression(expr, t); 
			} else {
				Get();
				Expression index; 
				Expression(out index);
				expr = new IndexerExpression(expr, index); 
				Expect(43);
			}
		}
	}



	public void Parse() {
		la = new Token();
		la.val = "";		
		Get();
		Grammar();

		Expect(0);
	}
	
	bool[,] set = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{T,T,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{T,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,T,T, T,x,x,x, x,T,x,T, x,T,T,x, x,x,T,x, x,T,x,x, x,x,x,x, x,x,x,x, x,T,T,x, x,x,x,T, T,x,x,x, x,x},
		{T,T,T,T, T,x,x,x, T,T,x,T, x,T,T,T, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,T,T,x, x,x,x,T, T,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,x, x,x,x,T, T,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, x,x}

	};
	
	
	void SynErr (int n) {
		if (errDist >= minErrDist) {
			string s;
			switch (n) {
			case 0: s = "EOF expected"; break;
			case 1: s = "identifier expected"; break;
			case 2: s = "number expected"; break;
			case 3: s = "string expected"; break;
			case 4: s = "\"(\" expected"; break;
			case 5: s = "\",\" expected"; break;
			case 6: s = "\")\" expected"; break;
			case 7: s = "\"{\" expected"; break;
			case 8: s = "\"}\" expected"; break;
			case 9: s = "\"next\" expected"; break;
			case 10: s = "\";\" expected"; break;
			case 11: s = "\"break\" expected"; break;
			case 12: s = "\"=\" expected"; break;
			case 13: s = "\"var\" expected"; break;
			case 14: s = "\"if\" expected"; break;
			case 15: s = "\"elseif\" expected"; break;
			case 16: s = "\"else\" expected"; break;
			case 17: s = "\"endif\" expected"; break;
			case 18: s = "\"while\" expected"; break;
			case 19: s = "\"endwhile\" expected"; break;
			case 20: s = "\"endw\" expected"; break;
			case 21: s = "\"return\" expected"; break;
			case 22: s = "\"or\" expected"; break;
			case 23: s = "\"||\" expected"; break;
			case 24: s = "\"and\" expected"; break;
			case 25: s = "\"&&\" expected"; break;
			case 26: s = "\"<>\" expected"; break;
			case 27: s = "\"!=\" expected"; break;
			case 28: s = "\"==\" expected"; break;
			case 29: s = "\">=\" expected"; break;
			case 30: s = "\">\" expected"; break;
			case 31: s = "\"<\" expected"; break;
			case 32: s = "\"<=\" expected"; break;
			case 33: s = "\"+\" expected"; break;
			case 34: s = "\"-\" expected"; break;
			case 35: s = "\"*\" expected"; break;
			case 36: s = "\"/\" expected"; break;
			case 37: s = "\"%\" expected"; break;
			case 38: s = "\"^\" expected"; break;
			case 39: s = "\"_true\" expected"; break;
			case 40: s = "\"_false\" expected"; break;
			case 41: s = "\".\" expected"; break;
			case 42: s = "\"[\" expected"; break;
			case 43: s = "\"]\" expected"; break;
			case 44: s = "??? expected"; break;
			case 45: s = "invalid Statement"; break;
			case 46: s = "invalid WhileLoopStatement"; break;
			case 47: s = "invalid ReturnStatement"; break;
			case 48: s = "invalid UnaryExpression"; break;
			case 49: s = "invalid AtomicExpression"; break;

				default: s = "error " + n; break;
			}
			Error(la.filename, la.line, la.col, n, s);
		}
		errDist = 0;
	}

	partial void Error(string filename, int line, int column, int errorCode, string message);
} // end Parser

}
namespace RobotBattle2.Rsl2 {
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

internal partial class Token {
	public int kind;    // token kind
	public int pos;     // token position in the source text (starting at 0)
	public int col;     // token column (starting at 0)
	public int line;    // token line (starting at 1)
	public string val;  // token value
	public Token next;  // ML 2005-03-11 Tokens are kept in linked list
	public string filename;
}

//-----------------------------------------------------------------------------------
// Buffer
//-----------------------------------------------------------------------------------
internal class Buffer {
	public const int EOF = -1;
	TextReader reader;      // input stream (seekable)
	bool isUserStream;  // was the stream opened by the user?
	int pos = 0;
	System.Text.StringBuilder innerBuffer;

	public Buffer(Stream s, bool isUserStream) {
		this.innerBuffer = new System.Text.StringBuilder();
		this.reader = new StreamReader(s, true);
		this.pos = 0;
		this.isUserStream = isUserStream;
	}

	public Buffer(TextReader s, bool isUserStream) {
		this.innerBuffer = new System.Text.StringBuilder();
		this.reader = s;
		this.pos = 0;
		this.isUserStream = isUserStream;
	}
	
	~Buffer() { Close(); }

	protected void Close() {
		if (!isUserStream && reader != null) {
			reader.Close();
			reader = null;
		}
	}

	public virtual int Read() {
		int value = Peek();
		if (value != EOF) {
			pos++;
		}
		return value;
	}

	public int Peek() {
		if (pos >= innerBuffer.Length) {
			int needed = (pos - innerBuffer.Length) + 1;
			char[] readbuf = new char[needed];
			int read = reader.Read(readbuf, 0, needed);
			innerBuffer.Append(readbuf, 0, read);
			if (read < needed) { return EOF; }
		}
		return innerBuffer[pos];
	}

	public int Pos {
		get { return pos; }
		set { pos = value; }
	}
}

//-----------------------------------------------------------------------------------
// Scanner
//-----------------------------------------------------------------------------------
internal partial class Scanner {
	const char EOL = '\n';
	const int eofSym = 0; /* pdt */
	const int maxT = 44;
	const int noSym = 44;


	public Buffer buffer; // scanner buffer
	
	Token t;          // current token
	int ch;           // current input character
	int pos;          // byte position of current character
	int col;          // column number of current character
	int line;         // line number of current character
	int oldEols;      // EOLs that appeared in a comment;
	Dictionary<int, int> start; // maps first token character to start state
	public string filename;

	Token tokens;     // list of tokens already peeked (first token is a dummy)
	Token pt;         // current peek token
	
	char[] tval = new char[128]; // text of current token
	int tlen;         // length of current token
	
	public Scanner (string filename) {
		this.filename = filename;
		Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
		buffer = new Buffer(stream, false);
		Init();
	}
	
	public Scanner (Stream s, string filename) {
		this.filename = filename;
		buffer = new Buffer(s, true);
		Init();
	}
	
	public Scanner (TextReader s, string filename) {
		this.filename = filename;
		buffer = new Buffer(s, true);
		Init();
	}
	
	void Init() {
		pos = -1; line = 1; col = 0;
		oldEols = 0;
		NextCh();
		start = new Dictionary<int, int>(128);
		for (int i = 65; i <= 90; ++i) start[i] = 1;
		for (int i = 95; i <= 95; ++i) start[i] = 1;
		for (int i = 97; i <= 122; ++i) start[i] = 1;
		for (int i = 48; i <= 57; ++i) start[i] = 2;
		start[46] = 35; 
		start[34] = 6; 
		start[40] = 11; 
		start[44] = 12; 
		start[41] = 13; 
		start[123] = 14; 
		start[125] = 15; 
		start[59] = 16; 
		start[61] = 36; 
		start[124] = 17; 
		start[38] = 19; 
		start[60] = 37; 
		start[33] = 22; 
		start[62] = 38; 
		start[43] = 27; 
		start[45] = 28; 
		start[42] = 29; 
		start[47] = 30; 
		start[37] = 31; 
		start[94] = 32; 
		start[91] = 33; 
		start[93] = 34; 
		start[Buffer.EOF] = -1;

		pt = tokens = new Token();  // first token is a dummy
	}
	
	Stack<StringBuilder> slurp = new Stack<StringBuilder>();
	public void BeginSlurp() { BeginSlurp(new StringBuilder()); }
	public void BeginSlurp(StringBuilder sb) { slurp.Push(sb); }
	public StringBuilder EndSlurp() { return slurp.Pop(); }
	
	void NextCh() {
		if (oldEols > 0) { ch = EOL; oldEols--; } 
		else {
			pos = buffer.Pos;
			ch = buffer.Read();
			if (slurp.Count > 0) {
				foreach (var sb in slurp) {
					sb.Append(ch);
				}
			}
			col++;
			// replace isolated '\r' by '\n' in order to make
			// eol handling uniform across Windows, Unix and Mac
			if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
			if (ch == EOL) { line++; col = 0; }
		}

	}

	void AddCh() {
		if (tlen >= tval.Length) {
			char[] newBuf = new char[2 * tval.Length];
			Array.Copy(tval, 0, newBuf, 0, tval.Length);
			tval = newBuf;
		}
		tval[tlen++] = (char)ch;
		NextCh();
	}



	bool Comment0() {
		int level = 1, pos0 = pos, line0 = line, col0 = col;
		NextCh();
		if (ch == '/') {
			NextCh();
			for(;;) {
				if (ch == 10) {
					level--;
					if (level == 0) { oldEols = line - line0; NextCh(); return true; }
					NextCh();
				} else if (ch == Buffer.EOF) return false;
				else NextCh();
			}
		} else {
			buffer.Pos = pos0; NextCh(); line = line0; col = col0;
		}
		return false;
	}

	bool Comment1() {
		int level = 1, pos0 = pos, line0 = line, col0 = col;
		NextCh();
		if (ch == '*') {
			NextCh();
			for(;;) {
				if (ch == '*') {
					NextCh();
					if (ch == '/') {
						level--;
						if (level == 0) { oldEols = line - line0; NextCh(); return true; }
						NextCh();
					}
				} else if (ch == Buffer.EOF) return false;
				else NextCh();
			}
		} else {
			buffer.Pos = pos0; NextCh(); line = line0; col = col0;
		}
		return false;
	}


	void CheckLiteral() {
		switch (t.val) {
			case "next": t.kind = 9; break;
			case "break": t.kind = 11; break;
			case "var": t.kind = 13; break;
			case "if": t.kind = 14; break;
			case "elseif": t.kind = 15; break;
			case "else": t.kind = 16; break;
			case "endif": t.kind = 17; break;
			case "while": t.kind = 18; break;
			case "endwhile": t.kind = 19; break;
			case "endw": t.kind = 20; break;
			case "return": t.kind = 21; break;
			case "or": t.kind = 22; break;
			case "and": t.kind = 24; break;
			case "_true": t.kind = 39; break;
			case "_false": t.kind = 40; break;
			default: break;
		}
	}

	Token NextToken() {
		while (ch == ' ' ||
			ch >= 9 && ch <= 10 || ch == 13 || ch == ' '
		) NextCh();
		if (ch == '/' && Comment0() ||ch == '/' && Comment1()) return NextToken();
		t = new Token();
		t.filename = filename;
		t.pos = pos; 
		t.col = col; 
		t.line = line; 
		int state;
		if (!start.TryGetValue(ch, out state)) { state = 0; }
		tlen = 0; AddCh();
		
		switch (state) {
			case -1: { t.kind = eofSym; break; } // NextCh already done
			case 0: { t.kind = noSym; break; }   // NextCh already done
			case 1:
				if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 1;}
				else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
			case 2:
				if (ch >= '0' && ch <= '9') {AddCh(); goto case 2;}
				else if (ch == '.') {AddCh(); goto case 3;}
				else {t.kind = 2; break;}
			case 3:
				if (ch >= '0' && ch <= '9') {AddCh(); goto case 4;}
				else {t.kind = noSym; break;}
			case 4:
				if (ch >= '0' && ch <= '9') {AddCh(); goto case 4;}
				else {t.kind = 2; break;}
			case 5:
				if (ch >= '0' && ch <= '9') {AddCh(); goto case 5;}
				else {t.kind = 2; break;}
			case 6:
				if (ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
				else if (ch == '"') {AddCh(); goto case 8;}
				else if (ch == 92) {AddCh(); goto case 7;}
				else {t.kind = noSym; break;}
			case 7:
				if (ch >= ' ' && ch <= '/' || ch >= '1' && ch <= 'w' || ch >= 'y' && ch <= '~') {AddCh(); goto case 6;}
				else if (ch == 'x') {AddCh(); goto case 9;}
				else if (ch == '0') {AddCh(); goto case 10;}
				else {t.kind = noSym; break;}
			case 8:
				{t.kind = 3; break;}
			case 9:
				if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f') {AddCh(); goto case 9;}
				else if (ch <= '!' || ch >= '#' && ch <= '/' || ch >= ':' && ch <= '@' || ch >= 'G' && ch <= '[' || ch >= ']' && ch <= '`' || ch >= 'g' && ch <= 65535) {AddCh(); goto case 6;}
				else if (ch == '"') {AddCh(); goto case 8;}
				else if (ch == 92) {AddCh(); goto case 7;}
				else {t.kind = noSym; break;}
			case 10:
				if (ch >= '0' && ch <= '7') {AddCh(); goto case 10;}
				else if (ch <= '!' || ch >= '#' && ch <= '/' || ch >= '8' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
				else if (ch == '"') {AddCh(); goto case 8;}
				else if (ch == 92) {AddCh(); goto case 7;}
				else {t.kind = noSym; break;}
			case 11:
				{t.kind = 4; break;}
			case 12:
				{t.kind = 5; break;}
			case 13:
				{t.kind = 6; break;}
			case 14:
				{t.kind = 7; break;}
			case 15:
				{t.kind = 8; break;}
			case 16:
				{t.kind = 10; break;}
			case 17:
				if (ch == '|') {AddCh(); goto case 18;}
				else {t.kind = noSym; break;}
			case 18:
				{t.kind = 23; break;}
			case 19:
				if (ch == '&') {AddCh(); goto case 20;}
				else {t.kind = noSym; break;}
			case 20:
				{t.kind = 25; break;}
			case 21:
				{t.kind = 26; break;}
			case 22:
				if (ch == '=') {AddCh(); goto case 23;}
				else {t.kind = noSym; break;}
			case 23:
				{t.kind = 27; break;}
			case 24:
				{t.kind = 28; break;}
			case 25:
				{t.kind = 29; break;}
			case 26:
				{t.kind = 32; break;}
			case 27:
				{t.kind = 33; break;}
			case 28:
				{t.kind = 34; break;}
			case 29:
				{t.kind = 35; break;}
			case 30:
				{t.kind = 36; break;}
			case 31:
				{t.kind = 37; break;}
			case 32:
				{t.kind = 38; break;}
			case 33:
				{t.kind = 42; break;}
			case 34:
				{t.kind = 43; break;}
			case 35:
				if (ch >= '0' && ch <= '9') {AddCh(); goto case 5;}
				else {t.kind = 41; break;}
			case 36:
				if (ch == '=') {AddCh(); goto case 24;}
				else {t.kind = 12; break;}
			case 37:
				if (ch == '>') {AddCh(); goto case 21;}
				else if (ch == '=') {AddCh(); goto case 26;}
				else {t.kind = 31; break;}
			case 38:
				if (ch == '=') {AddCh(); goto case 25;}
				else {t.kind = 30; break;}

		}
		t.val = new String(tval, 0, tlen);
		InitializeToken(t);
		return t;
	}
	
	partial void InitializeToken(Token token);
	
	// get the next token (possibly a token already seen during peeking)
	public Token Scan () {
		if (tokens.next == null) {
			return NextToken();
		} else {
			pt = tokens = tokens.next;
			return tokens;
		}
	}

	// peek for the next token, ignore pragmas
	public Token Peek () {
		if (pt.next == null) {
			do {
				pt = pt.next = NextToken();
			} while (pt.kind > maxT); // skip pragmas
		} else {
			do {
				pt = pt.next;
			} while (pt.kind > maxT);
		}
		return pt;
	}
	
	// make sure that peeking starts at the current scan position
	public void ResetPeek () { pt = tokens; }

} // end Scanner

}